package com.luych.toolbox.data.service.core.dm;

import com.luych.toolbox.common.enums.CaseType;
import com.luych.toolbox.common.enums.DataSourceType;
import com.luych.toolbox.data.service.core.CoreBuilder;
import com.luych.toolbox.data.service.core.CoreColumn;
import com.luych.toolbox.data.service.core.CoreTable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

public class DmTable implements CoreTable {

    private final String name;
    private final String comment;
    private final List<DmColumn> columns;
    private final String primaryKeyName;
    private final List<String> primaryKey;

    public DmTable(CoreTable coreTable) {
        this.name = coreTable.getName();
        this.comment = coreTable.getComment();
        this.columns = coreTable.getColumns().stream()
                .map(column -> (DmColumn) CoreBuilder.buildColumn(DataSourceType.DM, column))
                .collect(Collectors.toList());
        this.primaryKeyName = coreTable.getPrimaryKeyName();
        this.primaryKey = coreTable.getPrimaryKey();
    }

    public DmTable(String name, String comment, List<DmColumn> columns, String primaryKeyName, List<String> primaryKey) {
        this.name = name;
        this.comment = comment;
        this.columns = columns;
        this.primaryKeyName = primaryKeyName;
        this.primaryKey = primaryKey;
    }

    @Override
    public DataSourceType getDataSourceType() {
        return DataSourceType.DM;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getComment() {
        return comment;
    }

    @Override
    public List<DmColumn> getColumns() {
        return columns;
    }

    @Override
    public String getPrimaryKeyName() {
        return primaryKeyName;
    }

    @Override
    public List<String> getPrimaryKey() {
        return primaryKey;
    }

    @Override
    public String getPageSql(CaseType caseType, long pageSize, long pageNo) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";
        return "SELECT * FROM " + tableName + " LIMIT " + (pageNo - 1) * pageSize + ", " + pageSize + ";";
    }

    @Override
    public String getSelectSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";
        return "SELECT * FROM " + tableName + ";";
    }

    @Override
    public String getCountSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";
        return "SELECT COUNT(*) FROM " + tableName + ";";
    }

    @Override
    public String getTruncateSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";
        return "TRUNCATE TABLE " + tableName + ";";
    }

    @Override
    public String getInsertSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";
        String columns = this.getColumns().stream().map(CoreColumn::getName).sorted().map(caseType.getConvert())
                .map(columnName -> "\"" + columnName + "\"").collect(Collectors.joining(","));
        String values = this.getColumns().stream().map(c -> "?").collect(Collectors.joining(","));
        return "INSERT INTO " + tableName + "(" + columns + ") VALUES (" + values + ")";
    }

    @Override
    public String getCreateSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";

        String sql = "CREATE TABLE " + tableName + "(";
        StringJoiner joiner = new StringJoiner(",\n", "\n", "\n");
        for (DmColumn column : this.getColumns()) {
            String columnName = caseType.getConvert().apply(column.getName());
            columnName = "\"" + columnName + "\"";

            String joinerSql = "    " + columnName + " " + column.getColumnType();
            if (column.isIncrement()) {
                joinerSql += " IDENTITY(1, 1)";
            }
            if (column.isNullable()) {
                joinerSql += " NULL";
            } else {
                joinerSql += " NOT NULL";
            }
            joiner.add(joinerSql);
        }
        sql += joiner + ");";
        if (!CollectionUtils.isEmpty(this.getPrimaryKey())) {
            sql +=  "\n" +
                    "ALTER TABLE " + tableName +" " +
                    "ADD PRIMARY KEY (" + caseType.getConvert().apply(String.join(",", this.getPrimaryKey())) + ");";
        }

        if (!StringUtils.isEmpty(this.getComment())) {
            sql += "\nCOMMENT ON TABLE " + tableName + " IS '" + this.getComment() + "';";
        }
        for (DmColumn column : this.getColumns()) {
            String columnName = caseType.getConvert().apply(column.getName());
            columnName = "\"" + columnName + "\"";
            if (!StringUtils.isEmpty(column.getComment())) {
                sql += "\nCOMMENT ON COLUMN " + tableName + "." + columnName + " IS '" + column.getComment() + "';";
            }
        }
        return sql;
    }

    @Override
    public String getCommentSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";
        return "COMMENT ON TABLE " + tableName + " IS '" + this.getComment() +  "';";
    }

    @Override
    public String getRemoveSql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";
        return "DROP TABLE " + caseType.getConvert().apply(tableName) + ";";
    }

    @Override
    public String getCreatePrimaryKeySql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";
        return "ALTER TABLE " + tableName +
                " ADD PRIMARY KEY (" + caseType.getConvert().apply(String.join(",", this.getPrimaryKey())) + ");";
    }

    @Override
    public String getRemovePrimaryKeySql(CaseType caseType) {
        String tableName = caseType.getConvert().apply(this.getName());
        tableName = "\"" + tableName + "\"";

        String primaryKeyName = this.getPrimaryKeyName();
        primaryKeyName = "\"" + primaryKeyName + "\"";

        return "ALTER TABLE " + tableName +
                " DROP CONSTRAINT \"" + primaryKeyName + "\";";
    }
}
